home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 3D / SetupGL / SetupGL.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  31.5 KB  |  993 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SetupGL.c
  3.  
  4.     Contains:    Functions to enable building and destorying a GL full screen or windowed context
  5.  
  6.     Written by:    Geoff Stahl (ggs)
  7.  
  8.     Copyright:    Copyright © 1999 Apple Computer, Inc., All Rights Reserved
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     3/22/00    ggs     remove extranious prototype
  13.          <6>     3/21/00    ggs     Added windowed mode and clean up various implementation details
  14.          <5>     1/26/00    ggs     Add fade code back in, ensure NULL pointer/context/drawable
  15.                                     checks are in, add Preflight
  16.          <4>     1/24/00    ggs     Added glFinish to shutdown code
  17.          <3>     1/24/00    ggs     update to latest, better rendrere info handling for 3dfx, better
  18.                                     checks on pause and resume, added frin devce numer and gdhandle
  19.                                     from point
  20.             <2.7>   11/28/99    ggs     Split out DSp and error handling.  Added texture memory
  21.                                     considerations, assume VRAM is required if other than zero
  22.          <2.6>   11/14/99    ggs     Fix source server copy
  23.          <2.5>   11/13/99    ggs     fixed default pixel depth (0) condition that was causing failures
  24.          <2.4>   11/13/99    ggs     added custom fade code
  25.          <2.3>   11/13/99    ggs     Reset for Quake 3 use
  26.          <2.2>   11/12/99    ggs     re-add
  27.          <2.1>   11/12/99    ggs     added support for frequency retrieval, fixed display number
  28.                                     output to be correct if display number input was -1
  29.          <2>    11/12/99    ggs     1.0 functionality
  30.          <1>    11/11/99    ggs     Initial Add
  31.  
  32.     Disclaimer:    You may incorporate this sample code into your applications without
  33.                 restriction, though the sample code has been provided "AS IS" and the
  34.                 responsibility for its operation is 100% yours.  However, what you are
  35.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  36.                 after having made changes. If you're going to re-distribute the source,
  37.                 we require that you make it clear in the source that the code was
  38.                 descended from Apple Sample Code, but that you've made changes.
  39. */
  40.  
  41.  
  42. // system includes ----------------------------------------------------------
  43.  
  44.  
  45. // project includes ---------------------------------------------------------
  46.  
  47. #include "Error Handler.h"
  48. #include "SetupDSp.h"
  49. #include "SetupGL.h"
  50.  
  51.  
  52. // globals (internal/private) -----------------------------------------------
  53.  
  54. const RGBColor    rgbBlack    = { 0x0000, 0x0000, 0x0000 };
  55.  
  56. const short kWindowType = kWindowDocumentProc;
  57.  
  58.  
  59. // prototypes (internal/private) --------------------------------------------
  60.  
  61. static Boolean CheckRenderer (GDHandle hGD, long *VRAM, long *textureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust);
  62. static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust);
  63. static Boolean CheckWindowExtents (GDHandle hGD, short width, short height);
  64. static void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo);
  65.  
  66. static GLenum BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, GDHandle hGD, pstructGLInfo pcontextInfo);
  67. static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo);
  68. static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, 
  69.                             GDHandle hGD, pstructGLInfo pcontextInfo);
  70. static OSStatus BuildGLonDrawable (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo);
  71.                             
  72.  
  73. // functions (internal/private) ---------------------------------------------
  74.  
  75. // CheckRenderer
  76.  
  77. // looks at renderer attributes it has at least the VRAM is accelerated
  78.  
  79. // Inputs:     hGD: GDHandle to device to look at
  80. //            pVRAM: pointer to VRAM in bytes required; out is actual VRAM if a renderer was found, otherwise it is the input parameter
  81. //            pTextureRAM:  pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM)
  82. //            fAccelMust: do we check fro acceleration
  83.  
  84. // Returns: true if renderer for the requested device complies, false otherwise
  85.  
  86. static Boolean CheckRenderer (GDHandle hGD, long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust)
  87. {
  88.     AGLRendererInfo info, head_info;
  89.     GLint inum;
  90.     GLint dAccel = 0;
  91.     GLint dVRAM = 0, dMaxVRAM = 0;
  92.     Boolean canAccel = false, found = false;
  93.     
  94.     head_info = aglQueryRendererInfo(&hGD, 1);
  95.     aglReportError ();
  96.     if(!head_info)
  97.     {
  98.         ReportError ("aglQueryRendererInfo error");
  99.         return false;
  100.     }
  101.     else
  102.     {
  103.         info = head_info;
  104.         inum = 0;
  105.         // see if we have an accelerated renderer, if so ignore non-accelerated ones
  106.         // this prevents returning info on software renderer when actually we'll get the hardware one
  107.         while (info)
  108.         {    
  109.             aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
  110.             aglReportError ();
  111.             if (dAccel)
  112.                 canAccel = true;
  113.             info = aglNextRendererInfo(info);
  114.             aglReportError ();
  115.             inum++;
  116.         }
  117.             
  118.         info = head_info;
  119.         inum = 0;
  120.         while (info)
  121.         {    
  122.             aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
  123.             aglReportError ();
  124.             // if we can accel then we will choose the accelerated renderer 
  125.             // how about compliant renderers???
  126.             if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel)))
  127.             {
  128.                 
  129.                 aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM);    // we assume that VRAM returned is total thus add texture and VRAM required
  130.                 aglReportError ();
  131.                 if (dVRAM >= (*pVRAM + *pTextureRAM))
  132.                 {
  133.                     if (dVRAM >= dMaxVRAM) // find card with max VRAM
  134.                     {
  135.                         aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport);    // which depth buffer modes are supported
  136.                         aglReportError ();
  137.                         dMaxVRAM = dVRAM; // store max
  138.                         found = true;
  139.                     }
  140.                 }
  141.             }
  142.             info = aglNextRendererInfo(info);
  143.             aglReportError ();
  144.             inum++;
  145.         }
  146.     }
  147.     aglDestroyRendererInfo(head_info);
  148.     if (found) // if we found a card that has enough VRAM and meets the accel criteria
  149.     {
  150.         *pVRAM = dMaxVRAM; // return VRAM
  151.         return true;
  152.     }
  153.     // VRAM will remain to same as it did when sent in
  154.     return false;
  155. }
  156.  
  157. //-----------------------------------------------------------------------------------------------------------------------
  158.  
  159. // CheckAllDeviceRenderers
  160.  
  161. // looks at renderer attributes and each device must have at least one renderer that fits the profile
  162.  
  163. // Inputs:     pVRAM: pointer to VRAM in bytes required; out is actual min VRAM of all renderers found, otherwise it is the input parameter
  164. //            pTextureRAM:  pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM)
  165. //            fAccelMust: do we check fro acceleration
  166.  
  167. // Returns: true if any renderer for on each device complies (not necessarily the same renderer), false otherwise
  168.  
  169. static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust)
  170. {
  171.     AGLRendererInfo info, head_info;
  172.     GLint inum;
  173.     GLint dAccel = 0;
  174.     GLint dVRAM = 0, dMaxVRAM = 0;
  175.     Boolean canAccel = false, found = false, goodCheck = true; // can the renderer accelerate, did we find a valid renderer for the device, are we still successfully on all the devices looked at
  176.     long MinVRAM = 0x8FFFFFFF; // max long
  177.     
  178.     GDHandle hGD = GetDeviceList (); // get the first screen
  179.     while (hGD && goodCheck)
  180.     {
  181.                 
  182.         head_info = aglQueryRendererInfo(&hGD, 1);
  183.         aglReportError ();
  184.         if(!head_info)
  185.         {
  186.             ReportError ("aglQueryRendererInfo error");
  187.             return false;
  188.         }
  189.         else
  190.         {
  191.             info = head_info;
  192.             inum = 0;
  193.             // see if we have an accelerated renderer, if so ignore non-accelerated ones
  194.             // this prevents returning info on software renderer when actually we'll get the hardware one
  195.             while (info)
  196.             {    
  197.                 aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
  198.                 aglReportError ();
  199.                 if (dAccel)
  200.                     canAccel = true;
  201.                 info = aglNextRendererInfo(info);
  202.                 aglReportError ();
  203.                 inum++;
  204.             }
  205.                 
  206.             info = head_info;
  207.             inum = 0;
  208.             while (info)
  209.             {    
  210.                 aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel);
  211.                 aglReportError ();
  212.                 // if we can accel then we will choose the accelerated renderer 
  213.                 // how about compliant renderers???
  214.                 if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel)))
  215.                 {
  216.                     
  217.                     aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM);    // we assume that VRAM returned is total thus add texture and VRAM required
  218.                     aglReportError ();
  219.                     if (dVRAM >= (*pVRAM + *pTextureRAM))
  220.                     {
  221.                         if (dVRAM >= dMaxVRAM) // find card with max VRAM
  222.                         {
  223.                             aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport);    // which depth buffer modes are supported
  224.                             aglReportError ();
  225.                             dMaxVRAM = dVRAM; // store max
  226.                             found = true;
  227.                         }
  228.                     }
  229.                 }
  230.                 info = aglNextRendererInfo(info);
  231.                 aglReportError ();
  232.                 inum++;
  233.             }
  234.         }
  235.         aglDestroyRendererInfo(head_info);
  236.         if (found) // if we found a card that has enough VRAM and meets the accel criteria
  237.         {
  238.             if (MinVRAM > dMaxVRAM)
  239.                 MinVRAM = dMaxVRAM; // return VRAM
  240.             
  241.         }
  242.         else
  243.             goodCheck = false; // one device failed thus entire requirement fails
  244.         hGD = GetNextDevice (hGD); // get next device
  245.     } // while
  246.     if (goodCheck) // we check all devices and eeach was good
  247.     {
  248.         *pVRAM = dMaxVRAM; // return VRAM
  249.         return true;
  250.     }
  251.     return false; //at least one device failed to have mins
  252. }
  253.  
  254. //-----------------------------------------------------------------------------------------------------------------------
  255.  
  256. // CheckWindowExtents
  257.  
  258. // checks to see window fits on screen completely
  259.  
  260. // Inputs:     hGD: GDHandle to device to look at
  261. //            width/height: requested width and height of window
  262.  
  263. // Returns: true if window and borders fit, false otherwise
  264.  
  265. static Boolean CheckWindowExtents (GDHandle hGD, short width, short height)
  266. {
  267.     Rect strucRect, rectWin = {0, 0, 1, 1};
  268.     short deviceHeight = (**hGD).gdRect.bottom - (**hGD).gdRect.top - GetMBarHeight ();    
  269.     short deviceWidth = (**hGD).gdRect.right - (**hGD).gdRect.left;
  270.     short windowWidthExtra, windowHeightExtra;
  271.     // build window (not visible)
  272.     WindowPtr pWindow = NewCWindow (NULL, &rectWin, "\p", true, kWindowType, (WindowPtr)-1, 0, 0);
  273.     
  274.     strucRect = (**(((WindowPeek)pWindow)->strucRgn)).rgnBBox;
  275.     windowWidthExtra = (strucRect.right - strucRect.left) - 1;
  276.     windowHeightExtra = (strucRect.bottom - strucRect.top) - 1;
  277.     DisposeWindow (pWindow);
  278.     if ((width + windowWidthExtra <= deviceWidth) &&
  279.         (height + windowHeightExtra <= deviceHeight))
  280.         return true;
  281.     return false;
  282. }
  283.  
  284. // --------------------------------------------------------------------------
  285.  
  286. // DumpCurrent
  287.  
  288. // Kills currently allocated context
  289. // does not care about being pretty (assumes display is liekly faded)
  290.  
  291. // Inputs:     paglDraw, paglContext, pdspContext: things to be destroyed
  292.  
  293. void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo)
  294. {
  295.     if (*pdspContext)
  296.         DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks));
  297.  
  298.     if (*paglContext)
  299.     {
  300.         aglSetCurrentContext (NULL);
  301.         aglReportError ();
  302.         aglSetDrawable (*paglContext, NULL);
  303.         aglReportError ();
  304.         aglDestroyContext (*paglContext);
  305.         aglReportError ();
  306.         *paglContext = NULL;
  307.     }
  308.     
  309.     if (pcontextInfo->fmt)
  310.     {
  311.         aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer needed
  312.         aglReportError ();
  313.     }
  314.     pcontextInfo->fmt = 0;
  315.  
  316.     if (*paglDraw)
  317.         DisposeWindow ((WindowPtr)*paglDraw);
  318.     *paglDraw = NULL;
  319.  
  320.     DestroyDSpContext (pdspContext); // fades in
  321. }
  322.  
  323. #pragma mark -
  324. // --------------------------------------------------------------------------
  325.  
  326. // BuildGLContext
  327.  
  328. // Builds OpenGL context
  329.  
  330. // Inputs:     hGD: GDHandle to device to look at
  331. //            pcontextInfo: request and requirements for cotext and drawable
  332.  
  333. // Outputs: paglContext as allocated
  334. //            pcontextInfo:  allocated parameters
  335.  
  336. // if fail to allocate: paglContext will be NULL
  337. // if error: will return error paglContext will be NULL
  338.  
  339. static GLenum BuildGLContext (AGLDrawable* paglDraw, AGLContext* paglContext, GDHandle hGD, pstructGLInfo pcontextInfo)
  340. {
  341.     OSStatus err = noErr;
  342.  
  343.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
  344.     {
  345.         ReportError ("OpenGL not installed");
  346.         return noErr;
  347.     }    
  348.  
  349.     pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format
  350.     aglReportError ();
  351.     if (NULL == pcontextInfo->fmt) 
  352.     {
  353.         ReportError("Could not find valid pixel format");
  354.         return noErr;
  355.     }
  356.  
  357.     *paglContext = aglCreateContext (pcontextInfo->fmt, NULL);                // Create an AGL context
  358.     aglReportError ();
  359.     if (NULL == *paglContext) 
  360.     {
  361.         ReportError ("Could not create context");
  362.         return paramErr;
  363.     }
  364.     
  365.     // build window as late as possible
  366.     err = BuildDrawable (paglDraw, hGD, pcontextInfo);
  367.     if (err != noErr)
  368.     {
  369.         ReportError ("Could not build drawable");
  370.         return err;
  371.     }
  372.  
  373.     if (!aglSetDrawable (*paglContext, *paglDraw))                // attach the CGrafPtr to the context
  374.         return aglReportError ();
  375.     
  376.     if(!aglSetCurrentContext (*paglContext))                    // make the context the current context
  377.         return aglReportError ();
  378.  
  379.     
  380.     return err;
  381. }
  382.  
  383. // --------------------------------------------------------------------------
  384.  
  385. // BuildDrawable
  386.  
  387. // Builds window to be used as drawable
  388.  
  389. // Inputs:     hGD: GDHandle to device to look at
  390. //            pcontextInfo: request and requirements for cotext and drawable
  391.  
  392. // Outputs: paglDraw as allocated
  393. //            pcontextInfo:  allocated parameters
  394.  
  395. // if fail to allocate: paglDraw will be NULL
  396. // if error: will return error paglDraw will be NULL
  397.  
  398. static OSStatus BuildDrawable (AGLDrawable* paglDraw, GDHandle hGD, pstructGLInfo pcontextInfo)
  399. {
  400.     Rect rectWin;
  401.     RGBColor rgbSave;
  402.     GrafPtr pGrafSave;
  403.     OSStatus err = noErr;
  404.     
  405.     // center window in our context's gdevice
  406.     rectWin.top  = (**hGD).gdRect.top + ((**hGD).gdRect.bottom - (**hGD).gdRect.top) / 2; // v center
  407.     rectWin.top  -= pcontextInfo->height / 2;
  408.     rectWin.left  = (**hGD).gdRect.left + ((**hGD).gdRect.right - (**hGD).gdRect.left) / 2;    // h center
  409.     rectWin.left  -= pcontextInfo->width / 2;
  410.     rectWin.right = rectWin.left + pcontextInfo->width;
  411.     rectWin.bottom = rectWin.top + pcontextInfo->height;
  412.     
  413.     if (pcontextInfo->fFullscreen)
  414.         *paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0);
  415.     else
  416.         *paglDraw = (AGLDrawable) NewCWindow (NULL, &rectWin, "\p", 0, kWindowType, (WindowPtr)-1, 0, 0);
  417.  
  418.     ShowWindow ((GrafPtr)*paglDraw);
  419.     GetPort (&pGrafSave);
  420.     SetPort ((GrafPtr)*paglDraw);
  421.     GetForeColor (&rgbSave);
  422.     RGBForeColor (&rgbBlack);
  423.     PaintRect (&(*paglDraw)->portRect);
  424.     RGBForeColor (&rgbSave); // ensure color is reset for proper blitting
  425.     SetPort (pGrafSave);
  426.     return err;
  427. }
  428.  
  429. // --------------------------------------------------------------------------
  430.  
  431. // BuildGLonDevice
  432.  
  433. // Takes device single device and tries to build on it
  434.  
  435. // Inputs:     hGD: GDHandle to device to look at
  436. //            *pcontextInfo: request and requirements for cotext and drawable
  437.  
  438. // Outputs: *paglDraw, *paglContext and *pdspContext as allocated
  439. //            *pcontextInfo:  allocated parameters
  440.  
  441. // if fail to allocate: paglDraw, paglContext and pdspContext will be NULL
  442. // if error: will return error and paglDraw, paglContext and pdspContext will be NULL
  443.  
  444. static OSStatus BuildGLonDevice (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, 
  445.                             GDHandle hGD, pstructGLInfo pcontextInfo)
  446. {
  447.     GLint depthSizeSupport;
  448.     OSStatus err = noErr;
  449.     Boolean fCheckRenderer = false;
  450.  
  451.     if (pcontextInfo->fFullscreen)
  452.     {
  453.         // if we are in 16 or 32 bit mode already, we can check the renderer now (we will double check later)
  454.         if (16 <= (**(**hGD).gdPMap).pixelSize)
  455.         {
  456.             // check for VRAM and accelerated
  457.             if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
  458.             {
  459.                 ReportError ("Renderer check failed");
  460.                 return err;
  461.             }
  462.             else
  463.                 fCheckRenderer = true;
  464.         }
  465.         
  466.         err = BuildDSpContext (pdspContext, hGD, depthSizeSupport, pcontextInfo);
  467.         // we are now faded
  468.         if ((err != noErr) || (*pdspContext == NULL))
  469.         {
  470.             if (err != noErr)
  471.                 ReportErrorNum ("BuildDSpContext failed with error:", err);
  472.             else
  473.                 ReportError ("Could not build DrawSprocket context");
  474.             if (*pdspContext)
  475.                 DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  476.             return err;
  477.         }
  478.     }
  479.     else
  480.     {
  481.         if (pcontextInfo->pixelDepth == 0)    // default
  482.         {
  483.             pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
  484.             if (16 > pcontextInfo->pixelDepth)
  485.                 pcontextInfo->pixelDepth = 16;
  486.         }
  487.         if (pcontextInfo->fDepthMust && (pcontextInfo->pixelDepth != (**(**hGD).gdPMap).pixelSize))    // device depth must match and does not
  488.         {
  489.             ReportError ("Pixel Depth does not match device in windowed mode.");
  490.             if (*pdspContext)
  491.                 DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  492.             return err;
  493.         }
  494.         // copy back the curretn depth
  495.         pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
  496.         if (!CheckWindowExtents (hGD, pcontextInfo->width, pcontextInfo->height))
  497.         {
  498.             ReportError ("Window will not fit on device in windowed mode.");
  499.             if (*pdspContext)
  500.                 DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  501.             return err;
  502.         }
  503.     }
  504.     
  505.     // if we have not already checked the renderer, check for VRAM and accelerated
  506.     if (!fCheckRenderer)
  507.         if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
  508.         {
  509.             ReportError ("Renderer check failed");
  510.             if (*pdspContext)
  511.                 DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  512.             return err;
  513.         }
  514.     
  515.     // do agl
  516.     err = BuildGLContext (paglDraw, paglContext, hGD, pcontextInfo);
  517.     
  518.     if (*pdspContext)
  519.         DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  520.     
  521.     return err;
  522. }
  523.  
  524.  
  525. // --------------------------------------------------------------------------
  526.  
  527. // BuildGLonDrawable
  528.  
  529. // Takes a drawable and tries to build on it
  530.  
  531. // Inputs:     aglDraw: a valid AGLDrawable
  532. //            *pcontextInfo: request and requirements for cotext and drawable
  533.  
  534. // Outputs: *paglContext as allocated
  535. //            *pcontextInfo:  allocated parameters
  536.  
  537. // if fail to allocate: paglContext will be NULL
  538. // if error: will return error and paglContext will be NULL
  539.  
  540. static OSStatus BuildGLonDrawable (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo)
  541. {
  542.     GDHandle hGD = NULL;
  543.     short numDevices;
  544.     GLint depthSizeSupport;
  545.     OSStatus err = noErr;
  546.     
  547.     if (!aglDraw || !pcontextInfo)
  548.     {
  549.         ReportError ("NULL parameter passed to BuildGLonDrawable.");
  550.         return paramErr;
  551.     }
  552.  
  553.     // check renderere VRAM and acceleration
  554.     numDevices = FindGDHandleFromWindow ((WindowPtr) aglDraw, &hGD);
  555.     // so what do we do here?
  556.     if (!pcontextInfo->fDraggable)     // if numDevices > 1 then we will only using the software renderer otherwise check only window device
  557.     {
  558.         if ((numDevices > 1) || (numDevices == 0)) // this window spans mulitple devices thus will be software only
  559.         {
  560.             // infinite VRAM, infinite textureRAM, not accelerated
  561.             if (pcontextInfo->fAcceleratedMust)
  562.             {
  563.                 ReportError ("Unable to accelerate window that spans multiple devices");
  564.                 return err;
  565.             }
  566.         }
  567.         else // not draggable on single device
  568.         {
  569.             if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
  570.             {
  571.                 ReportError ("Renderer check failed");
  572.                 return err;
  573.             }
  574.         }
  575.     }
  576.     // else draggable so must check all for support (each device should have at least one renderer that meets the requirements)
  577.     else if (!CheckAllDeviceRenderers (&(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust))
  578.     {
  579.         ReportError ("Renderer check failed");
  580.         return err;
  581.     }
  582.     
  583.     // do agl
  584.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
  585.     {
  586.         ReportError ("OpenGL not installed");
  587.         return NULL;
  588.     }    
  589.     // we successfully passed the renderer check
  590.  
  591.     if (!pcontextInfo->fDraggable && (numDevices == 1))  // not draggable on a single device
  592.         pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format
  593.     else
  594.         pcontextInfo->fmt = aglChoosePixelFormat (NULL, 0, pcontextInfo->aglAttributes); // get an appropriate pixel format
  595.     aglReportError ();
  596.     if (NULL == pcontextInfo->fmt) 
  597.     {
  598.         ReportError("Could not find valid pixel format");
  599.         return NULL;
  600.     }
  601.  
  602.     *paglContext = aglCreateContext (pcontextInfo->fmt, NULL); // Create an AGL context
  603.     aglReportError ();
  604.     if (NULL == *paglContext) 
  605.     {
  606.         ReportError ("Could not create context");
  607.         return NULL;
  608.     }
  609.     
  610.     if (!aglSetDrawable (*paglContext, aglDraw)) // attach the CGrafPtr to the context
  611.         return aglReportError ();
  612.     
  613.     if(!aglSetCurrentContext (*paglContext)) // make the context the current context
  614.         return aglReportError ();
  615.  
  616.     return err;
  617. }
  618.  
  619. #pragma mark -
  620.  
  621. // functions (public) -------------------------------------------------------
  622.  
  623. // PreflightGL
  624.  
  625. // Checks for presense of OpenGL and DSp (if required)
  626. // Inputs: checkFullscreen: true if one wants to run fullscreen (which requires DrwSprocket currently)
  627. // Ouputs: true if OpenGL is installed (and DrawSprocket if checkFullscreen is true
  628.  
  629. Boolean PreflightGL (Boolean checkFullscreen)
  630. {
  631.     if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
  632.         return false;
  633.     if (checkFullscreen && ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup)) // check for existance of DSp
  634.         return false;
  635.     return true;
  636. }
  637.  
  638. // --------------------------------------------------------------------------
  639.  
  640. // BuildGL
  641.  
  642. // Takes device and geometry request and tries to build best context and drawable
  643. // if device does not work will walk down devices looking for first one that satisfies requirments
  644.  
  645. // Inputs:     *pnumDevice: 0 any device, # attempt that device first, then any device
  646. //            *pcontextInfo: request and requirements for cotext and drawable
  647.  
  648. // Outputs: *paglDraw, *paglContext and *pdspContext as allocated
  649. //            *pnumDevice to device number in list that was used 
  650. //            *pcontextInfo:  allocated parameters
  651.  
  652. // if fail to allocate: paglDraw, paglContext and pdspContext will be NULL
  653. // if error: will return error and paglDraw, paglContext and pdspContext will be NULL
  654.  
  655. OSStatus BuildGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, 
  656.                   short* pnumDevice, pstructGLInfo pcontextInfo)
  657. {
  658.     GDHandle hGD = NULL;
  659.     OSStatus err = noErr;
  660.     structGLInfo contextInfoSave;
  661.     
  662.     // clear
  663.     *paglDraw = 0;
  664.     *paglContext = 0;
  665.     *pdspContext = 0;
  666.     contextInfoSave = *pcontextInfo; // save info to reset on failures
  667.     
  668.     if (pcontextInfo->fFullscreen)
  669.     {
  670.         err = StartDSp ();
  671.         if (gDSpStarted)
  672.             gNeedFade = true;
  673.         else
  674.             return err;
  675.     }
  676.     
  677.     //find main device
  678.     if (*pnumDevice == -1)
  679.     {
  680.         GDHandle hDevice; // check number of screens
  681.         hGD = GetMainDevice ();
  682.         if (NULL != hGD)
  683.         {
  684.             err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo);
  685.             // find device number
  686.             *pnumDevice = 0;
  687.             hDevice = DMGetFirstScreenDevice (true);
  688.             do
  689.             {
  690.                 if (hDevice == hGD)
  691.                     break;
  692.                 hDevice = DMGetNextScreenDevice (hDevice, true);
  693.                 (*pnumDevice)++;
  694.             }
  695.             while (hDevice);
  696.             if (!hDevice)
  697.                 ReportError ("main device match not found");
  698.         }
  699.         else
  700.             ReportError ("Cannot get main device");
  701.     }
  702.  
  703.     if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0))
  704.     {
  705.         *pcontextInfo = contextInfoSave; // restore info
  706.         //find target device and check this first is one exists
  707.         if (*pnumDevice)
  708.         {
  709.             short i;
  710.             hGD = DMGetFirstScreenDevice (true);
  711.             for (i = 0; i < *pnumDevice; i++)
  712.             {
  713.                 GDHandle hGDNext = DMGetNextScreenDevice (hGD, true);
  714.                 if (NULL == hGDNext) // ensure we did not run out of devices
  715.                     break; // if no more devices drop out
  716.                 else
  717.                     hGD = hGDNext; // otherwise continue
  718.             }
  719.             *pnumDevice = i; // record device we actually got
  720.             err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo);
  721.         }
  722.     }
  723.     
  724.     // while we have not allocated a context or there were errors
  725.     if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0))
  726.     {
  727.         DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have
  728.         *pcontextInfo = contextInfoSave; // restore info
  729.         // now look through the devices in order
  730.         hGD = DMGetFirstScreenDevice (true);    
  731.         *pnumDevice = -1;
  732.         do 
  733.         {
  734.             (*pnumDevice)++;
  735.             err = BuildGLonDevice (paglDraw, paglContext, pdspContext, hGD, pcontextInfo);
  736.             if ((err != noErr) || (*paglDraw == 0) || (*paglContext == 0))    // reset hGD only if we are not done
  737.             {
  738.                 hGD = DMGetNextScreenDevice (hGD, true);
  739.                 DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo); // dump what ever partial solution we might have
  740.                 *pcontextInfo = contextInfoSave; // restore info
  741.             }
  742.         }
  743.         while (((err != noErr) || (*paglDraw == 0) || (*paglContext == 0)) && hGD);
  744.     }
  745.     
  746.     return err;
  747. }
  748.  
  749. // --------------------------------------------------------------------------
  750.  
  751. // DestroyGL
  752.  
  753. // Destroys drawable and context
  754. // Ouputs: *paglDraw, *paglContext and *pdspContext should be 0 on exit
  755.  
  756. OSStatus DestroyGL (AGLDrawable* paglDraw, AGLContext* paglContext, DSpContextReference* pdspContext, pstructGLInfo pcontextInfo)
  757. {
  758.     if ((!paglContext) || (!*paglContext))
  759.         return paramErr; // not a valid context
  760.     glFinish ();
  761.     DumpCurrent (paglDraw, paglContext, pdspContext, pcontextInfo);
  762.     ShutdownDSp ();
  763.     return noErr;
  764. }
  765.  
  766. //-----------------------------------------------------------------------------------------------------------------------
  767.  
  768. // BuildGLFromWindow
  769.  
  770. // Takes window in the form of an AGLDrawable and geometry request and tries to build best context
  771.  
  772. // Inputs:     aglDraw: a valid AGLDrawable (i.e., a WindowPtr)
  773. //            *pcontextInfo: request and requirements for cotext and drawable
  774.  
  775. // Outputs: *paglContext as allocated
  776. //            *pcontextInfo:  allocated parameters
  777.  
  778. // if fail to allocate: paglContext will be NULL
  779. // if error: will return error and paglContext will be NULL
  780.  
  781. OSStatus BuildGLFromWindow (AGLDrawable aglDraw, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo)
  782. {
  783.     if (!aglDraw)
  784.         return paramErr;
  785.     return BuildGLonDrawable (aglDraw, paglContext, pcontextInfo);
  786. }
  787.  
  788. // --------------------------------------------------------------------------
  789.  
  790. // DestroyGLFromWindow
  791.  
  792. // Destroys context that waas allocated with BuildGLFromWindow
  793. // Ouputs: *paglContext should be NULL on exit
  794.  
  795. OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo)
  796. {
  797.     OSStatus err;
  798.     
  799.     if ((!paglContext) || (!*paglContext))
  800.         return paramErr; // not a valid context
  801.     glFinish ();
  802.     aglSetCurrentContext (NULL);
  803.     err = aglReportError ();
  804.     aglSetDrawable (*paglContext, NULL);
  805.     err = aglReportError ();
  806.     aglDestroyContext (*paglContext);
  807.     err = aglReportError ();
  808.     *paglContext = NULL;
  809.     
  810.     if (pcontextInfo->fmt)
  811.     {
  812.         aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer valid
  813.         err = aglReportError ();
  814.     }
  815.     pcontextInfo->fmt = 0;
  816.     
  817.     return err;
  818. }
  819.  
  820. //-----------------------------------------------------------------------------------------------------------------------
  821.  
  822. // PauseGL
  823.  
  824. // Pauses gl to allow toolbox drawing
  825.  
  826. OSStatus PauseGL (AGLContext aglContext)
  827. {
  828.     if (aglContext)
  829.     {
  830.         glFinish (); // must do this to ensure the queue is complete
  831. //        aglSetDrawable(aglContext, NULL);
  832.         aglSetCurrentContext (NULL);
  833.         return aglReportError ();
  834.     }
  835.     return noErr;
  836. }
  837.  
  838. //-----------------------------------------------------------------------------------------------------------------------
  839.  
  840. // ResumeGL
  841.  
  842. // resumes gl to allow gl drawing
  843.  
  844. OSStatus ResumeGL (AGLDrawable aglDraw, AGLContext aglContext)
  845. {
  846.     #pragma unused (aglDraw)
  847.     if (aglContext)
  848.     {
  849.         aglSetCurrentContext (aglContext);
  850. //        aglSetDrawable(aglContext, aglDraw);
  851.         return aglReportError ();
  852.     }
  853.     return noErr;
  854. }
  855.  
  856. // --------------------------------------------------------------------------
  857.  
  858. // FindGDHandleFromRect
  859.  
  860. // Inputs:    a global Rect
  861.  
  862. // Outputs:    the GDHandle that that Rect is mostly on
  863.  
  864. // returns the number of devices that the Rect touches
  865.  
  866. short FindGDHandleFromRect (Rect * pRect, GDHandle * phgdOnThisDevice)
  867. {
  868.     Rect rectSect;
  869.     long greatestArea, sectArea;
  870.     short numDevices = 0;
  871.     GDHandle hgdNthDevice;
  872.     
  873.     if (!phgdOnThisDevice)
  874.         return NULL;
  875.         
  876.     *phgdOnThisDevice = NULL;
  877.     
  878.     hgdNthDevice = GetDeviceList ();
  879.     greatestArea = 0;
  880.     // check window against all gdRects in gDevice list and remember 
  881.     //  which gdRect contains largest area of window}
  882.     while (hgdNthDevice)
  883.     {
  884.         if (TestDeviceAttribute (hgdNthDevice, screenDevice))
  885.             if (TestDeviceAttribute (hgdNthDevice, screenActive))
  886.             {
  887.                 // The SectRect routine calculates the intersection 
  888.                 //  of the window rectangle and this gDevice 
  889.                 //  rectangle and returns TRUE if the rectangles intersect, 
  890.                 //  FALSE if they don't.
  891.                 SectRect (pRect, &(**hgdNthDevice).gdRect, &rectSect);
  892.                 // determine which screen holds greatest window area
  893.                 //  first, calculate area of rectangle on current device
  894.                 sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top);
  895.                 if (sectArea > 0)
  896.                     numDevices++;
  897.                 if (sectArea > greatestArea)
  898.                 {
  899.                     greatestArea = sectArea; // set greatest area so far
  900.                     *phgdOnThisDevice = hgdNthDevice; // set zoom device
  901.                 }
  902.                 hgdNthDevice = GetNextDevice(hgdNthDevice);
  903.             }
  904.     }
  905.     return numDevices;
  906. }
  907.  
  908. // --------------------------------------------------------------------------
  909.  
  910. // GetWindowDevice
  911.  
  912. // Inputs:    a valid WindowPtr
  913.  
  914. // Outputs:    the GDHandle that that window is mostly on
  915.  
  916. // returns the number of devices that the windows content touches
  917.  
  918. short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice)
  919. {
  920.     GrafPtr pgpSave;
  921.     Rect rectWind, rectSect;
  922.     long greatestArea, sectArea;
  923.     short numDevices = 0;
  924.     GDHandle hgdNthDevice;
  925.     
  926.     if (!pWindow || !phgdOnThisDevice)
  927.         return NULL;
  928.         
  929.     *phgdOnThisDevice = NULL;
  930.     
  931.     GetPort (&pgpSave);
  932.     SetPort (pWindow);
  933.     
  934.     rectWind = pWindow->portRect;
  935.     LocalToGlobal ((Point*)& rectWind.top);    // convert to global coordinates
  936.     LocalToGlobal ((Point*)& rectWind.bottom);
  937.     hgdNthDevice = GetDeviceList ();
  938.     greatestArea = 0;
  939.     // check window against all gdRects in gDevice list and remember 
  940.     //  which gdRect contains largest area of window}
  941.     while (hgdNthDevice)
  942.     {
  943.         if (TestDeviceAttribute (hgdNthDevice, screenDevice))
  944.             if (TestDeviceAttribute (hgdNthDevice, screenActive))
  945.             {
  946.                 // The SectRect routine calculates the intersection 
  947.                 //  of the window rectangle and this gDevice 
  948.                 //  rectangle and returns TRUE if the rectangles intersect, 
  949.                 //  FALSE if they don't.
  950.                 SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect);
  951.                 // determine which screen holds greatest window area
  952.                 //  first, calculate area of rectangle on current device
  953.                 sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top);
  954.                 if (sectArea > 0)
  955.                     numDevices++;
  956.                 if (sectArea > greatestArea)
  957.                 {
  958.                     greatestArea = sectArea; // set greatest area so far
  959.                     *phgdOnThisDevice = hgdNthDevice; // set zoom device
  960.                 }
  961.                 hgdNthDevice = GetNextDevice(hgdNthDevice);
  962.             }
  963.     }
  964.     
  965.     SetPort (pgpSave);
  966.     return numDevices;
  967. }
  968.  
  969. //-----------------------------------------------------------------------------------------------------------------------
  970.  
  971. // FindDeviceNumFromRect
  972.  
  973. // returns the number of the device that the point is on (i.e., where it is in the search order)
  974. // just a ultility to find the number of the device from a point
  975.  
  976. short FindDeviceNumFromRect (Rect * pRect)
  977. {
  978.     short displayNum = 0;
  979.     GDHandle hgdNthDevice, hgdFoundDevice;
  980.     
  981.     FindGDHandleFromRect (pRect, &hgdFoundDevice);
  982.     
  983.     hgdNthDevice = DMGetFirstScreenDevice (true);
  984.     while (hgdNthDevice)
  985.     {
  986.         if (hgdFoundDevice == hgdNthDevice)
  987.             break;
  988.         hgdNthDevice = DMGetNextScreenDevice(hgdNthDevice, true);
  989.         displayNum++;
  990.     }     // of WHILE
  991.  
  992.     return displayNum;
  993. }